package comm

import (
	"errors"
	"fmt"
	"gitee.com/gitee-go/utils"
	"io/ioutil"
	"os"
	"path/filepath"
	"runtime/debug"
	"strconv"

	"gitee.com/gitee-go/core"
	"gopkg.in/yaml.v2"
)

var (
	//MainCfg yaml config
	MainCfg *Conf
)

//Conf is main
type Conf struct {
	ServerConf *Server         `yaml:"server" json:"server"`
	RunnerConf *Runner         `yaml:"runner" json:"runner"`
	DataConf   *DataSourceConf `yaml:"datasource" json:"datasource"`
}

//DataSourceConf is DataSource
type DataSourceConf struct {
	Host     string `yaml:"host"`
	Port     string `yaml:"port"`
	Database string `yaml:"database"`
	Username string `yaml:"username"`
	Password string `yaml:"password"`
	ShowSQL  bool   `yaml:"showsql"`
}

//Runner conf
type Runner struct {
	Port       string `yaml:"port" json:"port"`
	Secret     string `yaml:"secret" json:"secret"`
	MainRunner bool   `yaml:"main-runner" json:"main-runner"`
}

//MainRunner conf
type MainRunnerConf struct {
	Enable    bool   `yaml:"enable"`
	Workspace string `yaml:"workspace"`
	Limit     int    `yaml:"limit"`
}

//Limit is Maximum number of coroutines
type Limit struct {
	BuildLimit int `yaml:"build" json:"build"`
	ParseLimit int `yaml:"parse" json:"parse"`
}

//Server Conf
type Server struct {
	Host      string `yaml:"host"`
	Port      string `yaml:"port"`
	LoginKey  string `yaml:"login-key" json:"login-key"`
	WorkPath  string `yaml:"workspace" json:"workspace"`
	LimitConf *Limit `yaml:"limit" json:"limit"`
}

/*
InitConf init conf
*/
func InitConf() (rterr error) {
	defer func() {
		if err := recover(); err != nil {
			core.LogPnc.Errorf("InitWorkPath:%+v", err)
			core.LogPnc.Errorf("%s", string(debug.Stack()))
			rterr = fmt.Errorf("recover:%v", err)
		}
	}()
	pth := existConf("")
	if pth == "" {
		pth = existConf(filepath.Join(utils.HomePath(), ".giteeGo"))
		/*if pth==""{
			pth=existConf("/etc/giteeGo")
		}*/
	}
	if pth == "" {
		return errors.New("not found application yaml config file")
	}
	bts, err := ioutil.ReadFile(pth)
	if err != nil {
		return err
	}

	cf := &Conf{}
	err = yaml.Unmarshal(bts, cf)
	if err != nil {
		return err
	}
	MainCfg = cf
	err = checkYmlConf()
	if err != nil {
		return err
	}
	initWorkPath()
	initLimit()
	Installed = true
	return nil
}

/*
checkYmlConf check Required parameters
*/
func checkYmlConf() error {
	if MainCfg == nil {
		return errors.New("yaml is empty")
	}
	if MainCfg.ServerConf == nil {
		return errors.New("server is empty")
	}
	if MainCfg.ServerConf.Host == "" {
		return errors.New("server Host is empty")
	}
	if MainCfg.ServerConf.Port == "" {
		return errors.New("server Port is empty")
	}
	spt, _ := strconv.Atoi(MainCfg.ServerConf.Port)
	if Port <= 0 && spt > 0 {
		Port = int32(spt)
	}
	if MainCfg.RunnerConf == nil {
		return errors.New("runner is empty")
	}
	if MainCfg.RunnerConf.Port == "" {
		return errors.New("runner Port is empty")
	}
	if MainCfg.RunnerConf.Secret == "" {
		return errors.New("runner Secret is empty")
	}

	if MainCfg.DataConf == nil {
		return errors.New("datasource is empty")
	}
	if MainCfg.DataConf.Host == "" {
		return errors.New("datasource : host is empty")
	}
	if MainCfg.DataConf.Port == "" {
		return errors.New("datasource : port is empty")
	}
	if MainCfg.DataConf.Username == "" {
		return errors.New("datasource : username is empty")
	}
	if MainCfg.DataConf.Password == "" {
		return errors.New("datasource : password is empty")
	}
	if MainCfg.DataConf.Database == "" {
		return errors.New("datasource : database is empty")
	}

	return nil

}

func existConf(dir string) string {
	var err error
	if dir == "" {
		_, err = os.Stat("application.yaml")
		if !os.IsNotExist(err) {
			return "application.yaml"
		}
		_, err = os.Stat("application.yml")
		if !os.IsNotExist(err) {
			return "application.yml"
		}
	} else {
		pth := filepath.Join(dir, "application.yaml")
		_, err = os.Stat(pth)
		if !os.IsNotExist(err) {
			return pth
		}
		pth = filepath.Join(dir, "application.yml")
		_, err = os.Stat(pth)
		if !os.IsNotExist(err) {
			return pth
		}
	}
	return ""
}
